package com.CoreryBlack.aspect;

import com.CoreryBlack.Mapper.OperateLogMapper;
import com.CoreryBlack.po.OperateLog;
import com.CoreryBlack.util.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * @Description LogAspect
 * @Author CoreryBlack
 * @Date 2024-09-23
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("@annotation(com.CoreryBlack.anno.Log)")
    public void pt(){}

    //注入请求对象

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private OperateLogMapper operateLogMapper;

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        //1.定义日志记录对象，封装数据
        OperateLog operateLog = new OperateLog();
        //获取请求头中的token
        String token = request.getHeader("token");
        //解析token得到载荷
        Claims claims = JwtUtils.parseJWT(token);
        //解析载荷得到登录人id
        Integer empId = (Integer) claims.get("id");
        //封装操作人 operate_user(登录人id)
        operateLog.setOperateUser(empId);
        //封装操作时间 operate_time(当前时间)
        operateLog.setOperateTime(LocalDateTime.now());
        //封装目标方法类全名 class_name
        operateLog.setClassName(pjp.getTarget().getClass().getName());
        //封装目标方法名 method_name
        operateLog.setMethodName(pjp.getSignature().getName());
        //封装目标方法参数 method_params(参数数组转换字符串存储封装)
        Object[] args = pjp.getArgs();
        String argsStr = Arrays.toString(args);
        operateLog.setMethodParams(argsStr);
        //记录开始毫秒数
        long start = System.currentTimeMillis();

        //2.执行目标方法获取返回结果
        Object result = pjp.proceed();

        //记录结果毫秒数
        long end = System.currentTimeMillis();

        //封装目标方法返回结果对象(转换为字符串存储)
        operateLog.setReturnValue(result.toString());
        //封装耗时时间(毫秒数)
        operateLog.setCostTime(end - start);

        //3.调用mapper插入数据库
        operateLogMapper.insert(operateLog);

        //4.返回结果
        return result;
    }
}
